/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = db2_core.c                                                    */
/*  NOTE      = DRDA协议解析                                                  */
/*  DATE      = 2015/03/18 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>

#include "frservice_comm.h"
#include "db2_core.h"
#include "db2_comm.h"
#include "db2_request.h"
#include "db2_response.h"
#include "config.h"

#define DB2_HASH_COUNT          100    /* 最大hash个数 */
#define DB2_MAX_BUFF_SIZE       1024 * 1024

extern void *g_p_apm_context;

/*******************************************************************************
*  FUNC     :  Check DDM code point
*  ARGS     :  i_ddm_cp(DDM code point)
*           :  p_i_req_res(request还是response)
*  RTN      :  FR_SUCC       (normal)
*              FR_FAIL       (error)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __db2_chk_cp(int i_ddm_cp, int *p_i_req_res)
{
    /* Check DDM code point */
    switch (i_ddm_cp)
    {
        /* DDM command start */
        case DRDA_CP_ACCRDB:
        case DRDA_CP_ACCSEC:
        case DRDA_CP_BGNBND:
        case DRDA_CP_BNDCPY:
        case DRDA_CP_BNDDPLY:
        case DRDA_CP_BNDSQLSTT:
        case DRDA_CP_CLSQRY:
        case DRDA_CP_CNTQRY:
        case DRDA_CP_DRPPKG:
        case DRDA_CP_DSCRDBTBL:
        case DRDA_CP_DSCSQLSTT:
        case DRDA_CP_ENDBND:
        case DRDA_CP_EXCSAT:
        //case DRDA_CP_EXCSQLGET:
        case DRDA_CP_EXCSQLIMM:
        case DRDA_CP_EXCSQLSET:
        case DRDA_CP_EXCSQLSTT:
        case DRDA_CP_GETNXTCHK:
        case DRDA_CP_INTRDBRQS:
        case DRDA_CP_OPNQRY:
        case DRDA_CP_PRPSQLSTT:
        case DRDA_CP_RDBCMM:
        case DRDA_CP_RDBRLLBCK:
        case DRDA_CP_REBIND:
        case DRDA_CP_SECCHK:
        case DRDA_CP_SNDPKT:
        case DRDA_CP_SYNCCTL:
        case DRDA_CP_SYNCRSY:
        /* DDM command end */
        /* Command data objects start */
        case DRDA_CP_BNDOPT:
        case DRDA_CP_SQLSTTVRB:
        case DRDA_CP_OUTOVR:
        case DRDA_CP_SQLTBLNAM:
        case DRDA_CP_SQLDTA:
        case DRDA_CP_PRCNAM:
        case DRDA_CP_SQLATTR:
        case DRDA_CP_RDBNAM:
        case DRDA_CP_LOGNAM:
        case DRDA_CP_LOGTSTMP:
        case DRDA_CP_SNAADDR:
        case DRDA_CP_IPADDR:
        case DRDA_CP_TCPHOST:
        case DRDA_CP_CNNTKN:
        /* Command data objects end */
            *p_i_req_res = DB2_REQUEST;
            return FR_SUCC;

        /* Reply data objects start */
        case DRDA_CP_SQLCARD:
        case DRDA_CP_ACCSECRD:
        case DRDA_CP_MGRLVLOVR:
        case DRDA_CP_MONITORRD:
        case DRDA_CP_QRYDTA:
        case DRDA_CP_SQLDARD:
        case DRDA_CP_EXCSATRD:
        case DRDA_CP_QRYDSC:
        case DRDA_CP_SQLCINRD:
        case DRDA_CP_SQLDTARD:
        case DRDA_CP_SQLRSLRD:
        case DRDA_CP_SYNCCRD:
        case DRDA_CP_SYNCTYPE:
        case DRDA_CP_XARETVAL:
        case DRDA_CP_PRPHRCLST:
        case DRDA_CP_RSYNCTYP:
        case DRDA_CP_UOWID:
        case DRDA_CP_UOWSTATE:
        case DRDA_CP_KERSECPPL:
        /* Reply data objects end */
        /* Reply messages start */
        case DRDA_CP_ACCRDBRM:
        case DRDA_CP_RDBUPDRM:
        case DRDA_CP_ENDQRYRM:
        case DRDA_CP_CMMRQSRM:
        case DRDA_CP_ENDUOWRM:
        case DRDA_CP_OPNQRYRM:
        case DRDA_CP_RSLSETRM:
        case DRDA_CP_ENDDTARM:
        case DRDA_CP_CMDCMPRM:
        case DRDA_CP_CMDVLTRM:
        case DRDA_CP_SECCHKRM:
        /* Reply messages end */
        /* Reply error messages start */
        case DRDA_CP_AGNPRMRM:
        case DRDA_CP_CMDATHRM:
        case DRDA_CP_CMDCHKRM:
        case DRDA_CP_CMDNSPRM:
        case DRDA_CP_MGRDEPRM:
        case DRDA_CP_PRCCNVRM:
        case DRDA_CP_PRMNSPRM:
        case DRDA_CP_RDBACCRM:
        case DRDA_CP_RDBAFLRM:
        case DRDA_CP_RDBATHRM:
        case DRDA_CP_RDBNFNRM:
        case DRDA_CP_RSCLMTRM:
        case DRDA_CP_SYNTAXRM:
        case DRDA_CP_TRGNSPRM:
        case DRDA_CP_VALNSPRM:
        case DRDA_CP_INVRQSRM:
        case DRDA_CP_ABNUOWRM:
        case DRDA_CP_BGNBNDRM:
        case DRDA_CP_OBJNSPRM:
        case DRDA_CP_PKGBPARM:
        case DRDA_CP_RDBNACRM:
        case DRDA_CP_SQLERRRM:
        case DRDA_CP_DTAMCHRM:
        case DRDA_CP_PKGBNARM:
        case DRDA_CP_QRYNOPRM:
        case DRDA_CP_MGRLVLRM:
        case DRDA_CP_DSCINVRM:
        case DRDA_CP_INTTKNRM:
        case DRDA_CP_OPNQFLRM:
        case DRDA_CP_QRYPOPRM:
        /* Reply error messages end */
            *p_i_req_res = DB2_RESPONSE;
            return FR_SUCC;

        /* common object start */
        case DRDA_CP_SECTKNOVR:
        case DRDA_CP_SQLSTT:
        case DRDA_CP_TYPDEFNAM:
        case DRDA_CP_TYPDEFOVR:
        case DRDA_CP_EXTDTA:
        case DRDA_CP_SECTKN:
        case DRDA_CP_PKTOBJ:
        case DRDA_CP_SYNCLOG:
        case DRDA_CP_C004:
        /* common object end */
            *p_i_req_res = DB2_UNKNOW;
            return FR_SUCC;

        /* DB2协议定义以外 */
        default:
            return FR_FAIL;
    }
}

/*******************************************************************************
*  FUNC     :  初始化私有DB2 session
*  ARGS     :  p_st_session(DB2私有session)
*  RTN      :  FR_SUCC       (normal)
*              FR_FAIL       (error)
*  NOTE     :  p_st_session必须不为NULL
*******************************************************************************/
FR_STATIC int __db2_init_private(L7_session *p_st_session)
{
    Frhash_header *p_st_prepare_hash = NULL;             /* prepare hash */
    L7_fragment_db2 *p_st_fragment = NULL;               /* 分片包相关数据 */
    L7session_db2  *p_st_db2_conn = NULL;                /* 链接信息 */
    L7session_db2_private *p_st_private_session = NULL;  /* DB2私有session */

    /* 申请整个私有session结构的内存 */
    p_st_private_session = (L7session_db2_private *)frmalloc(sizeof(L7session_db2_private));
    if (p_st_private_session == NULL)
    {
        goto error;
    }
    memset(p_st_private_session, 0x00, sizeof(L7session_db2_private));

    /* 申请链路信息结构内存 */
    p_st_db2_conn = (L7session_db2 *)frmalloc(sizeof(L7session_db2));
    if (p_st_db2_conn == NULL)
    {
        goto error;
    }
    memset(p_st_db2_conn, 0x00, sizeof(L7session_db2));
    /* 设置默认的CSSID为EBCDIC(CP500) */
    snprintf(p_st_db2_conn->arr_ccsid
             , sizeof(p_st_db2_conn->arr_ccsid)
             , "%s", "CP500");
    /* 设置默认客户端的typdef */
    p_st_db2_conn->i_cli_typdef = DRDA_TYPDEF_QTDSQLASC;
    /* 设置默认服务端端的typdef */
    p_st_db2_conn->i_ser_typdef = DRDA_TYPDEF_QTDSQLX86;

    /* 申请分片包信息结构内存 */
    p_st_fragment = (L7_fragment_db2 *)frmalloc(sizeof(L7_fragment_db2));
    if (p_st_fragment == NULL)
    {
        goto error;
    }
    memset(p_st_fragment, 0x00, sizeof(L7_fragment_db2));
    p_st_fragment->i_next_correlator = 1;
    p_st_fragment->i_req_resp_flg = DB2_UNKNOW;
    p_st_fragment->i_last_ddm_flg = DB2_FALSE;
    p_st_fragment->i_exter_flg = DB2_FALSE;
    p_st_fragment->i_exter_whole_flg = DB2_FALSE;

    /* 创建prepare hash */
    p_st_prepare_hash = frhash2_create2(DB2_HASH_COUNT);
    if (p_st_prepare_hash == NULL)
    {
        goto error;
    }

    /* 设置初始化结构 */
    p_st_private_session->p_st_sess = p_st_db2_conn;
    p_st_private_session->p_st_fragment = p_st_fragment;
    p_st_private_session->p_hash_prepare = p_st_prepare_hash;
    p_st_session->p_session_private = p_st_private_session;
    return FR_SUCC;

error:
    db2_free((void **)(&p_st_private_session));
    db2_free((void **)(&p_st_db2_conn));
    db2_free((void **)(&p_st_fragment));
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  初始化私有DB2 session
*  ARGS     :  p_st_private(私有session数据)
*  RTN      :  FR_SUCC       (normal)
*              FR_FAIL       (error)
*  NOTE     :  p_st_private必须不是NULL
*******************************************************************************/
FR_STATIC void __db2_destroy_curr_info(L7session_db2_private *p_st_private)
{
    if (p_st_private->p_st_req)
    {
        db2_destroy_request(&p_st_private->p_st_req);
    }
    if (p_st_private->p_st_resp)
    {
        db2_destroy_response(&p_st_private->p_st_resp);
    }
    db2_init_fragment(p_st_private->p_st_fragment);

    return;
}

/*******************************************************************************
*  FUNC     :  取得完整的packet包
*  ARGS     :  p_st_private(私有session数据)
*           :  p_data(当前数据包数据)
*           :  ui_len(当前数据包数据长度)
*           :  p_st_timestamp(当前数据包发生的时间点)
*           :  p_i_whole_flg(packet是否完整标识)
*  RTN      :  FR_FAIL (true)
*              FR_SUCC (false)
*  NOTE     :  解析失败后需要释放p_st_private里的request/response/fragment信息
*******************************************************************************/
FR_STATIC int __db2_set_analysis_data(L7session_db2_private *p_st_private
                                  , char *p_data
                                  , unsigned int ui_len
                                  , struct timeval *p_st_timestamp
                                  , int *p_i_whole_flg)
{
    int i_ret = FR_SUCC;
    uint16_t u16_cp = 0;
    uint8_t u8_format_id = 0;
    uint16_t u16_hdr_len = 0;
    uint16_t u16_ddm_len = 0;
    int i_extended_num = 0;
    uint32_t u32_extended_len = 0;
    uint64_t u64_extended_len = 0;
    unsigned int ui_extended_len = 0;
    uint16_t u16_rqsdrr = 0;
    int i_new_flag = DB2_FALSE;
    int i_cp_type = DB2_UNKNOW;
    unsigned int ui_packet_len_pre = 0;
    Frbyte_Packet *p_st_data = NULL;
    *p_i_whole_flg = DB2_FALSE;
    L7_fragment_db2 *p_st_fragment = p_st_private->p_st_fragment;

    /* 创建bytebuffer */
    if (p_st_fragment->p_st_data == NULL)
    {
        /* 做成bytebuffer */
        p_st_fragment->p_st_data = bytebuff_creat();
        if (p_st_fragment->p_st_data == NULL)
        {
            return FR_FAIL;
        }
        i_new_flag = DB2_TRUE;
        p_st_fragment->st_start_timestamp.tv_sec = p_st_timestamp->tv_sec;
        p_st_fragment->st_start_timestamp.tv_usec = p_st_timestamp->tv_usec;
    }

    p_st_data = p_st_fragment->p_st_data;
    /* 设置当前分片包时间点 */
    p_st_fragment->st_timestamp.tv_sec = p_st_timestamp->tv_sec;
    p_st_fragment->st_timestamp.tv_usec = p_st_timestamp->tv_usec;

    ui_packet_len_pre = bytebuff_length(p_st_data);
    /* 入力数据长度是0,不追加 */
    if (ui_len == 0)
    {
        frdbg("The input data length is 0!\n");
        return FR_SUCC;
    }

    /* 追加数据到buffer */
    i_ret = bytebuff_add(p_st_data, p_data, ui_len);
    if (i_ret != FR_SUCC)
    {
        return FR_FAIL;
    }

    /* 对于超长数据，不继续在做解析 */
    if (bytebuff_length(p_st_data) >= DB2_MAX_BUFF_SIZE)
    {
        frdbg("too large size!\n");
        return FR_FAIL;
    }

    if (p_st_fragment->i_exter_flg == DB2_TRUE
        && p_st_fragment->i_exter_whole_flg == DB2_FALSE)
    {
        return FR_SUCC;
    }

    /* 上个DDM的数据还未接收完成 */
    if (p_st_fragment->u64_remain_len)
    {
        /* 上一个DDM还所需的长度大于本次packet的长度 */
        if (p_st_fragment->u64_remain_len >= ui_len)
        {
            p_st_fragment->u64_remain_len -= ui_len;
            /* packet里的最后一个DDM已经接收完成 */
            if (p_st_fragment->i_last_ddm_flg == DB2_TRUE
                && p_st_fragment->u64_remain_len == 0)
            {
                *p_i_whole_flg = DB2_TRUE;
            }
            return FR_SUCC;
        }
        else
        {
            /* 如果上个DDM是packet的最后一个DDM,取了所需长度还有剩余,格式错误 */
            if (p_st_fragment->i_last_ddm_flg == DB2_TRUE)
            {
                frdbg("The data format is incorrect!\n");
                goto error;
            }
            else
            {
                /* 从本次次的第一个DDM开始 */
                bytebuff_setPosition(p_st_data, ui_packet_len_pre + p_st_fragment->u64_remain_len);
                p_st_fragment->u64_remain_len = 0;
            }
        }
    }
    /* 上个DDM的数据的数据头都还没接收完成 */
    else if (p_st_fragment->i_residual_ddm_head_len)
    {
        /* 从上次的最后一个DDM开始 */
        bytebuff_setPosition(p_st_data, ui_packet_len_pre - p_st_fragment->i_residual_ddm_head_len);
    }

    /* 初步解析DDM */
    while (bytebuff_remaining(p_st_data) >= DRDA_DDM_HD_LEN)
    {
        /* 取得DDM的长度(网络字节序) */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_hdr_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC || u16_hdr_len < DRDA_DDM_HD_LEN)
        {
            return FR_FAIL;
        }

        /* 跳过DDMID */
        bytebuff_skip(p_st_data, 1);
        /* 取得FORMATID */
        i_ret = bytebuff_get_char(p_st_data, &u8_format_id);
        if (i_ret != FR_SUCC)
        {
            return FR_FAIL;
        }
        /* 取得chained flag(0x40:01000000) */
        if (u8_format_id & 0x40)
        {
            p_st_fragment->i_last_ddm_flg = DB2_FALSE;
        }
        else
        {
            p_st_fragment->i_last_ddm_flg = DB2_TRUE;
        }

        /* 取得Indicate the DSS type */
        switch (u8_format_id & 0x0F)
        {
            /* 1: a Request DSS. */
            case 1:
                /*
                * 假如同一个packet中之前是resonance的DDM,
                * 先如今是request的DDM,当做格式错误处理.
                */
                if (p_st_fragment->i_req_resp_flg == DB2_RESPONSE)
                {
                    frdbg("The data format is incorrect!\n");
                    goto error;
                }
                p_st_fragment->i_req_resp_flg = DB2_REQUEST;
                break;

            /* 2: a Reply DSS. */
            case 2:
                /*
                * 假如同一个packet中之前是resonance的DDM,
                * 先如今是request的DDM,当做格式错误处理.
                */
                if (p_st_fragment->i_req_resp_flg == DB2_REQUEST)
                {
                    frdbg("The data format is incorrect!\n");
                    goto error;
                }
                p_st_fragment->i_req_resp_flg = DB2_RESPONSE;
                break;

            default:
                break;
        }

        /* 取得RQSDRR */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_rqsdrr, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            return FR_FAIL;
        }

        /* 判断correlator */
        if (u16_rqsdrr != p_st_fragment->i_next_correlator)
        {
            goto error;
        }

        /* 取得same correlator flag(0x10:00010000),设置correlator */
        if (!(u8_format_id & 0x10))
        {
            p_st_fragment->i_next_correlator += 1;
        }

        /* 取得DDM的长度 */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_ddm_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC || u16_ddm_len < 4)
        {
            return FR_FAIL;
        }

        /* 取得DDM的CP */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_cp, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            return FR_FAIL;
        }

        /* Check if this DDM has extended length field */
        if (u16_ddm_len & DB2_CONTINUATION_BIT)
        {
            i_extended_num = u16_ddm_len - DB2_CONTINUATION_BIT - 4;
            if (i_extended_num > bytebuff_remaining(p_st_data))
            {
                frdbg("The data format is incorrect!\n");
                goto error;
            }

            switch (i_extended_num)
            {
                case 8:
                case 6:
                    i_ret = bytebuff_get_long(p_st_data, i_extended_num
                                             , &u64_extended_len
                                             , BYTE_BIG_ENDIAN);
                    ui_extended_len = (unsigned int)u64_extended_len;
                    ui_extended_len += 2;
                    break;

                case 4:
                    i_ret = bytebuff_get_int(p_st_data, i_extended_num
                                            , &u32_extended_len
                                            , BYTE_BIG_ENDIAN);
                    ui_extended_len = (unsigned int)u32_extended_len;
                    ui_extended_len += 2;
                    break;

                case 0:
                    if (u16_cp != DRDA_CP_EXTDTA && u16_cp != DRDA_CP_QRYDTA)
                    {
                        frdbg("The data format is incorrect!\n");
                        goto error;
                    }
                    if (u16_hdr_len & DB2_CONTINUATION_BIT)
                    {
                        p_st_fragment->i_exter_flg = DB2_TRUE;
                    }
                    ui_extended_len = u16_hdr_len - DRDA_DDM_HD_LEN;
                    break;

                default:
                    frdbg("The data format is incorrect!\n");
                    goto error;

            }

            if (i_ret != FR_SUCC)
            {
                frdbg("The data format is incorrect!\n");
                goto error;
            }
        }
        else if (u16_ddm_len != u16_hdr_len - 6)/* 长度判断 */
        {
            frdbg("The data format is incorrect!\n");
            goto error;
        }
        else
        {
            ui_extended_len = u16_ddm_len - 4;
        }

        /* 判断CODE POINT */
        i_ret = __db2_chk_cp(u16_cp, &i_cp_type);
        if (i_ret != FR_SUCC)
        {
            frdbg("The data format is incorrect!\n");
            goto error;
        }

        /* 在可知方向的情况下设置方向 */
        if (p_st_fragment->i_req_resp_flg != DB2_UNKNOW)
        {
            /* 前后取得方向不一致 */
            if (i_cp_type != DB2_UNKNOW
                && p_st_fragment->i_req_resp_flg != i_cp_type)
            {
                frdbg("The data format is incorrect!\n");
                goto error;
            }
        }
        else
        {
            p_st_fragment->i_req_resp_flg = i_cp_type;
        }

        /* 判定是否是最后一个DDM */
        if (p_st_fragment->i_last_ddm_flg == DB2_TRUE)
        {
            /* 最后一个DDM,取了所需长度还有剩余,格式错误 */
            if (ui_extended_len < (unsigned int)bytebuff_remaining(p_st_data))
            {
                frdbg("The data format is incorrect!\n");
                goto error;
            }
            /* 取完一个完整的packet */
            else if (ui_extended_len == (unsigned int)bytebuff_remaining(p_st_data))
            {
                p_st_fragment->u64_remain_len = 0;
                p_st_fragment->i_residual_ddm_head_len = 0;
                *p_i_whole_flg = DB2_TRUE;
                return FR_SUCC;
            }
            /* 还需要最后一个DDM的packet */
            else
            {
                p_st_fragment->u64_remain_len = ui_extended_len - bytebuff_remaining(p_st_data);
                p_st_fragment->i_residual_ddm_head_len = 0;
                return FR_SUCC;
            }
        }
        else
        {
            if (ui_extended_len <= (unsigned int)bytebuff_remaining(p_st_data))
            {
                p_st_fragment->u64_remain_len = 0;
                bytebuff_skip(p_st_data, ui_extended_len);
            }
            else
            {
                p_st_fragment->u64_remain_len = ui_extended_len - bytebuff_remaining(p_st_data);
                p_st_fragment->i_residual_ddm_head_len = 0;
                return FR_SUCC;
            }
        }
    }

    p_st_fragment->i_residual_ddm_head_len = bytebuff_remaining(p_st_data);
    return FR_SUCC;

error:
    if (i_new_flag == DB2_FALSE)
    {
        __db2_destroy_curr_info(p_st_private);
        i_ret = __db2_set_analysis_data(p_st_private, p_data, ui_len
                                        , p_st_timestamp, p_i_whole_flg);
        return i_ret;
    }
    else
    {
        return FR_FAIL;
    }
}

/*******************************************************************************
*  FUNC     :  判断当前数据链路是否是DRDA协议
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_packet(入力数据包)
*  RTN      :  APM_L7_IS_NO   (NO)
*              APM_L7_IS_YES  (YES)
*  NOTE     :
*******************************************************************************/
int db2_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    int i_ret = FR_SUCC;
    int i_matched_flg = DB2_FALSE;
    int i_same_correlator_flg_pre = DB2_FALSE;
    int i_same_correlator_flg_curr = DB2_FALSE;
    int i_dds_type = DB2_UNKNOW;
    int i_cp_type = DB2_UNKNOW;
    int i_extended_num = 0;
    uint64_t u64_extended_len = 0;
    uint32_t u32_extended_len = 0;
    unsigned int ui_extended_len = 0;
    uint8_t u8_ddm_id = 0;
    uint8_t u8_format_id = 0;
    uint16_t u16_hdr_len = 0;
    uint16_t u16_rqsdrr_pre = 0;
    uint16_t u16_rqsdrr_curr = 0;
    uint16_t u16_ddm_len = 0;
    uint16_t u16_cp = 0;
    Frbyte_Packet *p_st_data = NULL;
    unsigned int ui_len = 0;
    char *p_data = NULL;

    //入力参数检查
    if(p_st_packet == NULL || p_st_conn==NULL)
        return APM_L7_IS_NO;

    ui_len = p_st_packet->ui_payload_len; /* packet数据长度 */
    p_data = p_st_packet->p_payload;             /* packet数据内容 */

    /* 长度不足 */
    if (ui_len < DRDA_DDM_HD_LEN)
    {
        goto error;
    }

    p_st_data = bytebuff_creat();
    if (p_st_data == NULL)
    {
        frdbg("Create bytebuff failed!\n");
        goto error;
    }
    i_ret = bytebuff_add(p_st_data, p_data, ui_len);
    if (i_ret != FR_SUCC)
    {
        frdbg("Add data to bytebuff failed!\n");
        goto error;
    }

    /* DSSHDR syntax:LL(2-byte) DDMID(1-byte) FORMATID(1-byte) RQSDRR(2-byte) */
    /* 10(2 + 1 + 1 + 2 + 2 + 2) 分别表示LL + DDMID + FORMATID + RQSDRR
       + DDM的LL + DDM的CP */
    while (bytebuff_remaining(p_st_data) >= DRDA_DDM_HD_LEN)
    {
        /* 取得DDM的长度(网络字节序) */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_hdr_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC || u16_hdr_len < DRDA_DDM_HD_LEN)
        {
            goto error;
        }
        /* 判断长度(bytebuff_get_short时将长度本身跳过,此处判断需计算在内) */
        if (u16_hdr_len - 2 > bytebuff_remaining(p_st_data))
        {
            if (i_matched_flg == DB2_FALSE)
            {
                goto error;
            }
        }

        /* 取得DDMID */
        i_ret = bytebuff_get_char(p_st_data, &u8_ddm_id);
        if (i_ret != FR_SUCC)
        {
            goto error;
        }
        /* The DDMID field is always D0 for a DDM command */
        if (u8_ddm_id != 0xD0)
        {
            goto error;
        }

        /* 取得FORMATID */
        i_ret = bytebuff_get_char(p_st_data, &u8_format_id);
        if (i_ret != FR_SUCC)
        {
            goto error;
        }
        /*
        *  FORMATID 说明
        *  Bit 0: Unused.
        *  Bit 1: A flag. 1 indicates that the DSS structure is chained
        *         to the next structure. 0 indicates no chaining.
        *  Bit 2: A flag. 1 indicates to continue when errors occur
        *         , and 0, otherwise.
        *  Bit 3: A flag. 1 indicates that the next DSS has the same request
        *         correlator, and 0, otherwise. If bit 1 is 0, bit 3 is also 0.
        *  Bits 4 through 7 Indicate the DSS type:
        *         1: a Request DSS.
        *         2: a Reply DSS.
        *         3: an Object DSS.
        *         4: an Encrypted Object DSS
        */

        /* 取得chained flag(0x40:01000000) */
        if (!(u8_format_id & 0x40)
            && u16_hdr_len - 4 > bytebuff_remaining(p_st_data))
        {
            goto error;
        }

        /* 取得same correlator flag(0x10:00010000) */
        if (u8_format_id & 0x10)
        {
            i_same_correlator_flg_curr = DB2_TRUE;
        }
        else
        {
            i_same_correlator_flg_curr = DB2_FALSE;
        }

        /* 取得Indicate the DSS type */
        switch (u8_format_id & 0x0F)
        {
            /* 1: a Request DSS. */
            case 1:
                i_dds_type = DB2_REQUEST;
                break;

            /* 2: a Reply DSS. */
            case 2:
                i_dds_type = DB2_RESPONSE;
                break;

            default:
                break;
        }

        /* 取得RQSDRR */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_rqsdrr_curr, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            goto error;
        }

        /* 前后关联DDM格式判断 */
        if (i_matched_flg == DB2_FALSE)
        {
            if (i_same_correlator_flg_pre == DB2_TRUE)
            {
                if (u16_rqsdrr_curr != u16_rqsdrr_pre)
                {
                    goto error;
                }
            }
            else
            {
                if (u16_rqsdrr_curr != u16_rqsdrr_pre + 1)
                {
                    goto error;
                }
            }
        }
        else
        {
            i_matched_flg = DB2_TRUE;
        }

        /* 取得DDM的长度 */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_ddm_len, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC || u16_ddm_len < 4)
        {
            goto error;
        }

        /* 取得DDM的CP */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_cp, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            goto error;
        }

        /* Check if this DDM has extended length field */
        if (u16_ddm_len & DB2_CONTINUATION_BIT)
        {
            i_extended_num = u16_ddm_len - DB2_CONTINUATION_BIT - 4;
            if (i_extended_num > bytebuff_remaining(p_st_data))
            {
                goto error;
            }

            switch (i_extended_num)
            {
                case 8:
                case 6:
                    i_ret = bytebuff_get_long(p_st_data, i_extended_num
                                             , &u64_extended_len
                                             , BYTE_BIG_ENDIAN);
                    ui_extended_len = (unsigned int)u64_extended_len;
                    ui_extended_len += 2;
                    break;

                case 4:
                    i_ret = bytebuff_get_int(p_st_data, i_extended_num
                                            , &u32_extended_len
                                            , BYTE_BIG_ENDIAN);
                    ui_extended_len = (unsigned int)u32_extended_len;
                    ui_extended_len += 2;
                    break;

                case 0:
                    if (u16_cp != DRDA_CP_EXTDTA && u16_cp != DRDA_CP_QRYDTA)
                    {
                        frdbg("The data format is incorrect!\n");
                        goto error;
                    }
                    ui_extended_len = u16_hdr_len - DRDA_DDM_HD_LEN;
                    break;

                default:
                    frdbg("The data format is incorrect!\n");
                    goto error;

            }

            if (i_ret != FR_SUCC)
            {
                frdbg("The data format is incorrect!\n");
                goto error;
            }
        }
        else if (u16_ddm_len != u16_hdr_len - 6)/* 长度判断 */
        {
            goto error;
        }
        else
        {
            ui_extended_len = u16_ddm_len;
        }

        /* 判断CODE POINT */
        i_ret = __db2_chk_cp(u16_cp, &i_cp_type);
        if (i_ret != FR_SUCC)
        {
            goto error;
        }


        /* 在可知方向的情况下设置方向 */
        if (i_cp_type != DB2_UNKNOW)
        {
            i_dds_type = i_cp_type;
        }

        /* 跳过DDM内容 */
        if (ui_extended_len - 4 < (unsigned int)bytebuff_remaining(p_st_data))
        {
            bytebuff_skip(p_st_data, ui_extended_len - 4);
        }
        else
        {
            break;
        }

        /* 设置前DDM信息 */
        u16_rqsdrr_pre = u16_rqsdrr_curr;
        i_same_correlator_flg_pre = i_same_correlator_flg_curr;
    }

    /* 设置方向 */
    if(frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        if (i_dds_type == DB2_RESPONSE)
        {
            i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip
                                     , p_st_packet->src_port);
        }
        else if (i_dds_type == DB2_REQUEST)
        {
            i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip
                                    , p_st_packet->dst_port);
        }

        if (i_ret != FR_SUCC)
            frdbg("Set server ip and port failed!\n");
    }
    bytebuff_free(&p_st_data);
    frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
    return APM_L7_IS_YES;

error:
    bytebuff_free(&p_st_data);
    /* 有可能方向未知 */
    i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
    if (i_ret == FR_SUCC)
    {
        frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
        return APM_L7_IS_YES;
    }
    i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
    if (i_ret == FR_SUCC)
    {
        frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
        return APM_L7_IS_YES;
    }
    return APM_L7_IS_NO;
}

/*******************************************************************************
*  FUNC     :  DB2的packet解析
*  ARGS     :  p_st_conn(入力链接信息)
            :  p_st_packet(入力packet信息)
            :  p_st_hash_report(保存Frreport_data)
*  RTN      :  参照module.h
*  NOTE     :
*******************************************************************************/
int db2_analysis(Conntrack *p_st_conn
                , Apm_packet *p_st_packet
                , Frhash_header *p_st_hash_report)
{
    int i_ret = FR_SUCC;
    int i_whole_flg = DB2_FALSE;
    L7_session *p_st_session = NULL;              /* L7session */
    L7session_db2_private *p_st_private = NULL;   /* DB2的私有数据 */

    if(p_st_conn == NULL || p_st_packet == NULL
        || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;
    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /*
    * 如果入力p_st_packet是FIN包, 说明本次DB2的connection结束,
    * 释放本次session信息. 如果入力p_st_packet是SYN包,
    * 说明新的DB2的connection开始了, 释放上次可能残留的session信息
    */
    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN
        || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        /* 销毁所有相关本次DB2的connection的数据 */
        db2_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    /* 本次链路的第一个有效packet包,创建链路 */
    if (p_st_session->p_session_private == NULL)
    {
        /* 初始化DB2的私有数据 */
        i_ret = __db2_init_private(p_st_session);
        if (i_ret != FR_SUCC)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        /* 设置session ID */
        fruuid(p_st_session->arr_session_id);
    }

    p_st_private = (L7session_db2_private *)p_st_session->p_session_private;
    /* 设置解析数据 */
    i_ret = __db2_set_analysis_data(p_st_private
                                   , p_st_packet->p_payload
                                   , p_st_packet->ui_payload_len
                                   , &(p_st_packet->st_timestamp)
                                   , &i_whole_flg);
    if (i_ret != FR_SUCC)
    {
        frdbg("__db2_set_analysis_data failed\n");
        __db2_destroy_curr_info(p_st_private);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 解析packet */
    switch (p_st_private->p_st_fragment->i_req_resp_flg)
    {
        case DB2_REQUEST: /* 解析request */
            i_ret = db2_parse_request(p_st_conn, p_st_hash_report
                                      , p_st_private, i_whole_flg);
            if (i_ret == APM_L7_ANALYZE_FAIL)
            {
                frdbg("Parse request failed\n");
                __db2_destroy_curr_info(p_st_private);
                return APM_L7_ANALYZE_FAIL;
            }
            break;

        case DB2_RESPONSE: /* 解析response */
            i_ret = db2_parse_response(p_st_conn, p_st_hash_report
                                      , p_st_private, i_whole_flg);
            if (i_ret == APM_L7_ANALYZE_FAIL)
            {
                frdbg("Parse response failed\n");
                __db2_destroy_curr_info(p_st_private);
                return APM_L7_ANALYZE_FAIL;
            }
            break;

        default: /* 类型未知 */
            /*
            * 如果当前数的packet还不能判断是客户端还是服务端的,
            * 且还有后续未接收完了的packet,本次packet先不做解析,
            * 留待下次确定了在做数据解析.
            */
            if (i_whole_flg == DB2_FALSE)
            {
                return APM_L7_ANALYZE_TODO;
            }
            /*
            * packet接收完了还是不能判断是客户端还是服务端的,
            * 当做错误的packet处理,实际正常情况不会发生.
            */
            else
            {
                frdbg("Unknow whether it's request or response!\n");
                /* request 已经创建当做是response解析 */
                if (p_st_private->p_st_req)
                {
                    i_ret = db2_parse_response(p_st_conn, p_st_hash_report
                                              , p_st_private, i_whole_flg);
                    if (i_ret == APM_L7_ANALYZE_FAIL)
                    {
                        frdbg("Parse response failed\n");
                        __db2_destroy_curr_info(p_st_private);
                        return APM_L7_ANALYZE_FAIL;
                    }
                }
                /* request未创建当做是request解析 */
                else
                {
                    i_ret = db2_parse_request(p_st_conn, p_st_hash_report
                                              , p_st_private, i_whole_flg);
                    if (i_ret == APM_L7_ANALYZE_FAIL)
                    {
                        frdbg("Parse request failed\n");
                        __db2_destroy_curr_info(p_st_private);
                        return APM_L7_ANALYZE_FAIL;
                    }
                }
            }
            break;
    }

    /* 返回 */
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  私有信息销毁
*  ARGS     :  p_private_session(DB2的私有session数据)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
int db2_session_destroy(void *p_private_session)
{
    L7session_db2_private *p_st_private = (L7session_db2_private *)p_private_session;

    /* 判断session是否为空 */
    if (p_st_private == NULL)
    {
        return FR_SUCC;
    }

    /* 销毁session数据 */
    if (p_st_private->p_st_sess)
    {
        db2_destroy_session(&(p_st_private->p_st_sess));
    }

    /* 销毁request数据 */
    if (p_st_private->p_st_req)
    {
        db2_destroy_request(&(p_st_private->p_st_req));
    }

    /* 销毁response数据 */
    if (p_st_private->p_st_resp)
    {
        db2_destroy_response(&p_st_private->p_st_resp);
    }

    /* 销毁分片数据 */
    if (p_st_private->p_st_fragment)
    {
        db2_destroy_fragment(&p_st_private->p_st_fragment);
    }

    /* 销毁prepare数据 */
    frhash2_free2(p_st_private->p_hash_prepare, frdb_statement_node_free);

    frfree(p_st_private);

    return FR_SUCC;
}
